unit Rails.DsConnection;

interface

uses
  Datasnap.DSproxyRest, System.Generics.Collections, Rails.ActiveRecord.Base,
  Datasnap.DSClientRest, System.SysUtils, RTTI, Cliente.Model;

type
    IDSRestCachedTObjectList<T> = interface;
    IDSRestCachedTUsers = interface;

    IDSRestCachedTObjectList<T> = interface(IDSRestCachedObject<TObjectList<TObject>>)
    end;

    TDSRestCachedTObjectList<T> = class(TDSRestCachedObject<TObjectList<TObject>>, IDSRestCachedTObjectList<TObject>, IDSRestCachedCommand)
    end;
    IDSRestCachedTUsers = interface(IDSRestCachedObject<TObject>)
    end;

    TDSRestCachedTUsers = class(TDSRestCachedObject<TObject>, IDSRestCachedTUsers, IDSRestCachedCommand)
    end;

type
  TDSRailsAdminRestClient<T: class> = class(TDSAdminRestClient)
  private
    TController_GetNewRecord: array [0..0] of TDSRestParameterMetaData;
    TController_GetNewRecord_Cache: array [0..0] of TDSRestParameterMetaData;
    TController_LoadAll: array [0..1] of TDSRestParameterMetaData;
    TController_LoadAll_Cache: array [0..1] of TDSRestParameterMetaData;
    TController_FindKey: array [0..3] of TDSRestParameterMetaData;
    TController_FindKey_Cache: array [0..3] of TDSRestParameterMetaData;
    TController_Save: array [0..2] of TDSRestParameterMetaData;
    TController_Delete: array [0..2] of TDSRestParameterMetaData;
    TController_DeleteById: array [0..2] of TDSRestParameterMetaData;

    FGetNewRecordCommand: TDSRestCommand;
    FGetNewRecordCommand_Cache: TDSRestCommand;
    FLoadAllCommand: TDSRestCommand;
    FLoadAllCommand_Cache: TDSRestCommand;
    FFindKeyCommand: TDSRestCommand;
    FFindKeyCommand_Cache: TDSRestCommand;
    FSaveCommand: TDSRestCommand;
    FDeleteCommand: TDSRestCommand;
    FDeleteByIdCommand: TDSRestCommand;
  public
    constructor Create;
    function GetNewRecord(const ARequestFilter: string = ''): TObject; virtual;
    function LoadAll(out Error: string; const ARequestFilter: string = ''): TObjectList<T>; virtual;
    destructor Destroy; override;
    function GetNewRecord_Cache(const ARequestFilter: string = ''): IDSRestCachedTUsers;
    function LoadAll_Cache(out Error: string; const ARequestFilter: string = ''): IDSRestCachedTObjectList<TObject>;
    function FindKey(Id: Integer; out ARecord: TObject; out Error: string; const ARequestFilter: string = ''): Boolean;
    function FindKey_Cache(Id: Integer; out ARecord: IDSRestCachedTUsers; out Error: string; const ARequestFilter: string = ''): Boolean;
    function Save(ARecord: TObject; out Error: string; const ARequestFilter: string = ''): Boolean;
    function Delete(ARecord: TObject; out Error: string; const ARequestFilter: string = ''): Boolean;
    function DeleteById(Id: string; out Error: string; const ARequestFilter: string = ''): Boolean;
  end;

  Controller = class(TCustomAttribute)
  public
    Name: string;
    constructor Create(Name: string);
  end;

  TController = class(TCustomAttribute)
  public
    class function GetName(AClass: TClass): string;
  end;

var
  DSRestConection: TDSRestConnection;

implementation

{ TDSRailsAdminRestClient<T> }

constructor TDSRailsAdminRestClient<T>.Create;
var
  ClassName: string;
begin
  inherited Create(DSRestConection);
  ClassName := TRttiContext.Create.GetType(TypeInfo(T)).AsInstance.MetaclassType.QualifiedClassName;
  
  TController_GetNewRecord[0].Name := '';
  TController_GetNewRecord[0].Direction := 4;
  TController_GetNewRecord[0].DBXType:= 37;
  TController_GetNewRecord[0].TypeName:= ClassName;
  TController_GetNewRecord_Cache[0].Name := '';
  TController_GetNewRecord_Cache[0].Direction := 4;
  TController_GetNewRecord_Cache[0].DBXType:= 26;
  TController_GetNewRecord_Cache[0].TypeName:= 'String';  

{  [0].Name := '';
  [0].Direction := 4;
  [0].DBXType:= 26;
  [0].TypeName:= 'String';    }

  TController_LoadAll[0].Name := 'Error';
  TController_LoadAll[0].Direction := 2;
  TController_LoadAll[0].DBXType:= 26;  
  TController_LoadAll[0].TypeName:= 'string';    
  TController_LoadAll[1].Name := '';
  TController_LoadAll[1].Direction := 4;  
  TController_LoadAll[1].DBXType:= 37;    
  TController_LoadAll[1].TypeName:= 'TObjectList<'+ClassName+'>';    

  TController_LoadAll_Cache[0].Name := 'Error';
  TController_LoadAll_Cache[0].Direction := 2;
  TController_LoadAll_Cache[0].DBXType:= 26;
  TController_LoadAll_Cache[0].TypeName:= 'string';   
  TController_LoadAll_Cache[1].Name := '';
  TController_LoadAll_Cache[1].Direction := 4;
  TController_LoadAll_Cache[1].DBXType:= 26;
  TController_LoadAll_Cache[1].TypeName:= 'String';     

  TController_FindKey[0].Name := 'Id';
  TController_FindKey[0].Direction := 1;
  TController_FindKey[0].DBXType:= 6;
  TController_FindKey[0].TypeName:= 'Integer';  
  TController_FindKey[1].Name := 'ARecord';
  TController_FindKey[1].Direction := 2;
  TController_FindKey[1].DBXType:= 37;
  TController_FindKey[1].TypeName:= ClassName;  
  TController_FindKey[2].Name := 'Error';
  TController_FindKey[2].Direction := 2;
  TController_FindKey[2].DBXType:= 26;
  TController_FindKey[2].TypeName:= 'string';      
  TController_FindKey[3].Name := '';
  TController_FindKey[3].Direction := 4;
  TController_FindKey[3].DBXType:= 4;
  TController_FindKey[3].TypeName:= 'Boolean';
{
TController_FindKey:
TController_FindKey_Cache:
TController_Save:
TController_Delete:
TController_DeleteById:

    TClientesController_FindKey: array [0..3] of TDSRestParameterMetaData =
    (
      (Name: 'Id'; Direction: 1; DBXType: 6; TypeName: 'Integer'),
      (Name: 'ARecord'; Direction: 2; DBXType: 37; TypeName: 'TObject'),
      (Name: 'Error'; Direction: 2; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );

    TClientesController_FindKey_Cache: array [0..3] of TDSRestParameterMetaData =
    (
      (Name: 'Id'; Direction: 1; DBXType: 6; TypeName: 'Integer'),
      (Name: 'ARecord'; Direction: 2; DBXType: 26; TypeName: 'String'),
      (Name: 'Error'; Direction: 2; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );

    TClientesController_Save: array [0..2] of TDSRestParameterMetaData =
    (
      (Name: 'ARecord'; Direction: 1; DBXType: 37; TypeName: 'TObject'),
      (Name: 'Error'; Direction: 2; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );

    TClientesController_Delete: array [0..2] of TDSRestParameterMetaData =
    (
      (Name: 'ARecord'; Direction: 1; DBXType: 37; TypeName: 'TObject'),
      (Name: 'Error'; Direction: 2; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );

    TClientesController_DeleteById: array [0..2] of TDSRestParameterMetaData =
    (
      (Name: 'Id'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: 'Error'; Direction: 2; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );



}

end;

function TDSRailsAdminRestClient<T>.GetNewRecord(const ARequestFilter: string = ''): TObject;
begin
  if FGetNewRecordCommand = nil then
  begin
    FGetNewRecordCommand := FConnection.CreateCommand;
    FGetNewRecordCommand.RequestType := 'GET';
    FGetNewRecordCommand.Text := Copy(Self.ClassName, 0, Pos('Client', Self.ClassName))+'.GetNewRecord';
    FGetNewRecordCommand.Prepare(TController_GetNewRecord);
  end;
  FGetNewRecordCommand.Execute('');
  if not FGetNewRecordCommand.Parameters[0].Value.IsNull then
  begin
    FUnMarshal := TDSRestCommand(FGetNewRecordCommand.Parameters[0].ConnectionHandler).GetJSONUnMarshaler;
    try
      Result := TObject(FUnMarshal.UnMarshal(FGetNewRecordCommand.Parameters[0].Value.GetJSONValue(True)));
      if FInstanceOwner then
        FGetNewRecordCommand.FreeOnExecute(Result);
    finally
      FreeAndNil(FUnMarshal)
    end
  end
  else
    Result := nil;
end;

function TDSRailsAdminRestClient<T>.LoadAll(
  out Error: string; const ARequestFilter: string = ''): TObjectList<T>;
begin
  if FLoadAllCommand = nil then
  begin
    FLoadAllCommand := FConnection.CreateCommand;
    FLoadAllCommand.RequestType := 'GET';
    FLoadAllCommand.Text := TController.GetName(Self.ClassType)+'.LoadAll';
    FLoadAllCommand.Prepare(TController_LoadAll);
  end;
  FLoadAllCommand.Execute('');
  Error := FLoadAllCommand.Parameters[0].Value.GetWideString;
  if not FLoadAllCommand.Parameters[1].Value.IsNull then
  begin
    FUnMarshal := TDSRestCommand(FLoadAllCommand.Parameters[1].ConnectionHandler).GetJSONUnMarshaler;
    try
      Result := TObjectList<T>(FUnMarshal.UnMarshal(FLoadAllCommand.Parameters[1].Value.GetJSONValue(True)));
      if FInstanceOwner then
        FLoadAllCommand.FreeOnExecute(Result);
    finally
      FreeAndNil(FUnMarshal)
    end
  end
  else
    Result := nil;
end;

function TDSRailsAdminRestClient<T>.GetNewRecord_Cache(const ARequestFilter: string): IDSRestCachedTUsers;
begin
  if FGetNewRecordCommand_Cache = nil then
  begin
    FGetNewRecordCommand_Cache := FConnection.CreateCommand;
    FGetNewRecordCommand_Cache.RequestType := 'GET';
    FGetNewRecordCommand_Cache.Text := 'TClientesController.GetNewRecord';
    FGetNewRecordCommand_Cache.Prepare(TController_GetNewRecord_Cache);
  end;
  FGetNewRecordCommand_Cache.ExecuteCache(ARequestFilter);
  Result := TDSRestCachedTUsers.Create(FGetNewRecordCommand_Cache.Parameters[0].Value.GetString);
end;

function TDSRailsAdminRestClient<T>.LoadAll_Cache(out Error: string; const ARequestFilter: string): IDSRestCachedTObjectList<TObject>;
begin
  if FLoadAllCommand_Cache = nil then
  begin
    FLoadAllCommand_Cache := FConnection.CreateCommand;
    FLoadAllCommand_Cache.RequestType := 'GET';
    FLoadAllCommand_Cache.Text := 'TClientesController.LoadAll';
    FLoadAllCommand_Cache.Prepare(TController_LoadAll_Cache);
  end;
  FLoadAllCommand_Cache.ExecuteCache(ARequestFilter);
  Error := FLoadAllCommand_Cache.Parameters[0].Value.GetWideString;
  Result := TDSRestCachedTObjectList<TObject>.Create(FLoadAllCommand_Cache.Parameters[1].Value.GetString);
end;

function TDSRailsAdminRestClient<T>.FindKey(Id: Integer; out ARecord: TObject; out Error: string; const ARequestFilter: string): Boolean;
begin
  if FFindKeyCommand = nil then
  begin
    FFindKeyCommand := FConnection.CreateCommand;
    FFindKeyCommand.RequestType := 'GET';
    FFindKeyCommand.Text := 'TClientesController.FindKey';
    FFindKeyCommand.Prepare(TController_FindKey);
  end;
  FFindKeyCommand.Parameters[0].Value.SetInt32(Id);
  FFindKeyCommand.Execute(ARequestFilter);
  if not FFindKeyCommand.Parameters[1].Value.IsNull then
  begin
    FUnMarshal := TDSRestCommand(FFindKeyCommand.Parameters[1].ConnectionHandler).GetJSONUnMarshaler;
    try
      ARecord := TObject(FUnMarshal.UnMarshal(FFindKeyCommand.Parameters[1].Value.GetJSONValue(True)));
      if FInstanceOwner then
        FFindKeyCommand.FreeOnExecute(ARecord);
    finally
      FreeAndNil(FUnMarshal)
    end;
  end
  else
    ARecord := nil;
  Error := FFindKeyCommand.Parameters[2].Value.GetWideString;
  Result := FFindKeyCommand.Parameters[3].Value.GetBoolean;
end;

function TDSRailsAdminRestClient<T>.FindKey_Cache(Id: Integer; out ARecord: IDSRestCachedTUsers; out Error: string; const ARequestFilter: string): Boolean;
begin
  if FFindKeyCommand_Cache = nil then
  begin
    FFindKeyCommand_Cache := FConnection.CreateCommand;
    FFindKeyCommand_Cache.RequestType := 'GET';
    FFindKeyCommand_Cache.Text := 'TClientesController.FindKey';
    FFindKeyCommand_Cache.Prepare(TController_FindKey_Cache);
  end;
  FFindKeyCommand_Cache.Parameters[0].Value.SetInt32(Id);
  FFindKeyCommand_Cache.ExecuteCache(ARequestFilter);
  ARecord := TDSRestCachedTUsers.Create(FFindKeyCommand_Cache.Parameters[1].Value.GetString);
  Error := FFindKeyCommand_Cache.Parameters[2].Value.GetWideString;
  Result := FFindKeyCommand_Cache.Parameters[3].Value.GetBoolean;
end;

function TDSRailsAdminRestClient<T>.Save(ARecord: TObject; out Error: string; const ARequestFilter: string): Boolean;
begin
  if FSaveCommand = nil then
  begin
    FSaveCommand := FConnection.CreateCommand;
    FSaveCommand.RequestType := 'POST';
    FSaveCommand.Text := 'TClientesController."Save"';
    FSaveCommand.Prepare(TController_Save);
  end;
  if not Assigned(ARecord) then
    FSaveCommand.Parameters[0].Value.SetNull
  else
  begin
    FMarshal := TDSRestCommand(FSaveCommand.Parameters[0].ConnectionHandler).GetJSONMarshaler;
    try
      FSaveCommand.Parameters[0].Value.SetJSONValue(FMarshal.Marshal(ARecord), True);
      if FInstanceOwner then
        ARecord.Free
    finally
      FreeAndNil(FMarshal)
    end
    end;
  FSaveCommand.Execute(ARequestFilter);
  Error := FSaveCommand.Parameters[1].Value.GetWideString;
  Result := FSaveCommand.Parameters[2].Value.GetBoolean;
end;

function TDSRailsAdminRestClient<T>.Delete(ARecord: TObject; out Error: string; const ARequestFilter: string): Boolean;
begin
  if FDeleteCommand = nil then
  begin
    FDeleteCommand := FConnection.CreateCommand;
    FDeleteCommand.RequestType := 'POST';
    FDeleteCommand.Text := 'TClientesController."Delete"';
    FDeleteCommand.Prepare(TController_Delete);
  end;
  if not Assigned(ARecord) then
    FDeleteCommand.Parameters[0].Value.SetNull
  else
  begin
    FMarshal := TDSRestCommand(FDeleteCommand.Parameters[0].ConnectionHandler).GetJSONMarshaler;
    try
      FDeleteCommand.Parameters[0].Value.SetJSONValue(FMarshal.Marshal(ARecord), True);
      if FInstanceOwner then
        ARecord.Free
    finally
      FreeAndNil(FMarshal)
    end
    end;
  FDeleteCommand.Execute(ARequestFilter);
  Error := FDeleteCommand.Parameters[1].Value.GetWideString;
  Result := FDeleteCommand.Parameters[2].Value.GetBoolean;
end;

function TDSRailsAdminRestClient<T>.DeleteById(Id: string; out Error: string; const ARequestFilter: string): Boolean;
begin
  if FDeleteByIdCommand = nil then
  begin
    FDeleteByIdCommand := FConnection.CreateCommand;
    FDeleteByIdCommand.RequestType := 'GET';
    FDeleteByIdCommand.Text := 'TClientesController.DeleteById';
    FDeleteByIdCommand.Prepare(TController_DeleteById);
  end;
  FDeleteByIdCommand.Parameters[0].Value.SetWideString(Id);
  FDeleteByIdCommand.Execute(ARequestFilter);
  Error := FDeleteByIdCommand.Parameters[1].Value.GetWideString;
  Result := FDeleteByIdCommand.Parameters[2].Value.GetBoolean;
end;

destructor TDSRailsAdminRestClient<T>.Destroy;
begin
  FreeAndNil(FGetNewRecordCommand);
  FreeAndNil(FGetNewRecordCommand_Cache);
  FreeAndNil(FLoadAllCommand);
  FreeAndNil(FLoadAllCommand_Cache);
  FreeAndNil(FFindKeyCommand);
  FreeAndNil(FFindKeyCommand_Cache);
  FreeAndNil(FSaveCommand);
  FreeAndNil(FDeleteCommand);
  FreeAndNil(FDeleteByIdCommand);
  inherited;
end;

{ Controller }

constructor Controller.Create(Name: string);
begin
  Self.Name := Name;
end;

{ TController }

class function TController.GetName(AClass: TClass): string;
var
  Ctx: TRttiContext;
  Typ: TRttiType;
  Attr: TCustomAttribute;
begin
  Ctx := TRttiContext.Create;
  Typ := Ctx.GetType(AClass);
  for Attr in Typ.GetAttributes do
  begin
    if Attr is Controller then
      Result := Controller(Attr).Name;
  end;

end;

end.
